<template>
  <div class="h-full flex flex-col px-5 pt-5 overflow-y-auto [&::-webkit-scrollbar]:hidden">
    <div class="pb-2 z-40" id="header">
      <NSpace>
        <NButton v-if="isProxy" secondary type="primary" @click.stop="close" style="--wails-draggable:no-drag">
          {{ t("index.close_grab") }}
        </NButton>
        <NButton v-else tertiary type="tertiary" @click.stop="open" style="--wails-draggable:no-drag">
          {{ t("index.open_grab") }}
        </NButton>
        <NSelect style="min-width: 100px;--wails-draggable:no-drag" :placeholder="t('index.grab_type')" v-model:value="resourcesType" multiple clearable
                 :max-tag-count="3" :options="classify"></NSelect>
        <n-popconfirm
            @positive-click="clear"
        >
          <template #trigger>
            <NButton tertiary type="error" style="--wails-draggable:no-drag">
              <template #icon>
                <n-icon>
                  <TrashOutline/>
                </n-icon>
              </template>
              {{ t("index.clear_list") }}
            </NButton>
          </template>
          {{ t("index.clear_list_tip") }}
        </n-popconfirm>
        <NButtonGroup style="--wails-draggable:no-drag">
          <NButton tertiary type="primary" @click.stop="batchDown">
            <template #icon>
              <n-icon>
                <DownloadOutline/>
              </n-icon>
            </template>
            {{ t('index.batch_download') }}
          </NButton>
          <NButton tertiary type="warning" @click.stop="batchExport">
            <template #icon>
              <n-icon>
                <ArrowRedoCircleOutline/>
              </n-icon>
            </template>
            {{ t('index.batch_export') }}
          </NButton>
          <NButton tertiary type="info" @click.stop="showImport=true">
            <template #icon>
              <n-icon>
                <ServerOutline/>
              </n-icon>
            </template>
            {{ t('index.batch_import') }}
          </NButton>
          <NButton tertiary :type="store.globalConfig.AutoDownload ? 'success' : 'default'" @click.stop="toggleAutoDownload">
            <template #icon>
              <n-icon>
                <FlashOutline/>
              </n-icon>
            </template>
            {{ t('index.auto_download_mode') }}
          </NButton>
        </NButtonGroup>
      </NSpace>
    </div>
    <div class="flex-1">
      <NDataTable
          :columns="columns"
          :data="filteredData"
          :bordered="false"
          :max-height="tableHeight"
          :row-key="rowKey"
          :virtual-scroll="true"
          :header-height="48"
          :height-for-row="()=> 48"
          :checked-row-keys="checkedRowKeysValue"
          @update:checked-row-keys="handleCheck"
          style="--wails-draggable:no-drag"
      />
    </div>
    <!-- <div class="flex justify-center items-center text-blue-400" id="bottom">
      <span class="cursor-pointer px-2 py-1" @click="BrowserOpenURL(certUrl)">{{ t('footer.cert_download') }}</span>
      <span class="cursor-pointer px-2 py-1" @click="BrowserOpenURL('https://github.com/putyy/res-downloader')">{{ t('footer.source_code') }}</span>
      <span class="cursor-pointer px-2 py-1" @click="BrowserOpenURL('https://github.com/putyy/res-downloader/issues')">{{ t('footer.help') }}</span>
      <span class="cursor-pointer px-2 py-1" @click="BrowserOpenURL('https://github.com/putyy/res-downloader/releases')">{{ t('footer.update_log') }}</span>
    </div> -->
    <Preview v-model:showModal="showPreviewRow" :previewRow="previewRow"/>
    <ShowLoading :loadingText="loadingText" :isLoading="loading"/>
    <ImportJson v-model:showModal="showImport" @submit="handleImport"/>
    <Password v-model:showModal="showPassword" @submit="handlePassword"/>
  </div>
</template>

<script lang="ts" setup>
import {NButton, NIcon, NImage, NInput, NSpace, NTooltip, NPopover} from "naive-ui"
import {computed, h, onMounted, ref, watch} from "vue"
import type {appType} from "@/types/app"
import type {DataTableRowKey, ImageRenderToolbarProps} from "naive-ui"
import Preview from "@/components/Preview.vue"
import ShowLoading from "@/components/ShowLoading.vue"
// @ts-ignore
import {getDecryptionArray} from '@/assets/js/decrypt.js'
import {useIndexStore} from "@/stores"
import appApi from "@/api/app"
import Action from "@/components/Action.vue"
import ActionDesc from "@/components/ActionDesc.vue"
import ImportJson from "@/components/ImportJson.vue"
import {useEventStore} from "@/stores/event"
import {BrowserOpenURL, ClipboardSetText} from "../../wailsjs/runtime"
import Password from "@/components/Password.vue"
import {useI18n} from 'vue-i18n'
import {
  DownloadOutline,
  ArrowRedoCircleOutline,
  ServerOutline,
  SearchOutline,
  TrashOutline,
  FlashOutline
} from "@vicons/ionicons5"

const {t} = useI18n()
const eventStore = useEventStore()
const isProxy = computed(() => {
  return store.isProxy
})
const certUrl = computed(() => {
  return store.baseUrl + "/api/cert"
})
const data = ref<any[]>([])
let filterClassify: string[] = []
const filteredData = computed(() => {
  let result = data.value

  if (filterClassify.length > 0) {
    result = result.filter(item => filterClassify.includes(item.Classify))
  }

  if (descriptionSearchValue.value) {
    result = result.filter(item => item.Description?.toLowerCase().includes(descriptionSearchValue.value.toLowerCase()))
  }

  return result
})

const store = useIndexStore()
const tableHeight = ref(800)
const resourcesType = ref<string[]>(["all"])

const classifyAlias: { [key: string]: any } = {
  image: computed(() => t("index.image")),
  audio: computed(() => t("index.audio")),
  video: computed(() => t("index.video")),
  m3u8: computed(() => t("index.m3u8")),
  live: computed(() => t("index.live")),
  xls: computed(() => t("index.xls")),
  doc: computed(() => t("index.doc")),
  pdf: computed(() => t("index.pdf")),
  font: computed(() => t("index.font"))
}

const dwStatus = computed<any>(() => {
  return {
    ready: t("index.ready"),
    running: t("index.running"),
    error: t("index.error"),
    done: t("index.done"),
    handle: t("index.handle")
  }
})

const maxConcurrentDownloads = computed(() => {
  return store.globalConfig.DownNumber
})

const classify = ref([
  {
    value: "all",
    label: computed(() => t("index.all")),
  },
])

const descriptionSearchValue = ref("")

const columns = ref<any[]>([
  {
    type: "selection",
  },
  {
    title: computed(() => t("index.domain")),
    key: "Domain",
    width: 90,
  },
  {
    title: computed(() => t("index.type")),
    key: "Classify",
    width: 80,
    filterOptions: computed(() => Array.from(classify.value).slice(1)),
    filterMultiple: true,
    filter: (value: string, row: appType.MediaInfo) => {
      if (!filterClassify.includes(value)) filterClassify.push(value)
      return !!~row.Classify.indexOf(String(value))
    },
    render: (row: appType.MediaInfo) => {
      const item = classify.value.find(item => item.value === row.Classify)
      return item ? item.label : row.Classify
    }
  },
  {
    title: computed(() => t("index.preview")),
    key: "Url",
    width: 80,
    render: (row: appType.MediaInfo) => {
      if (row.Classify === "image") {
        return h("div", {
          style: "width: 100%;max-height:80px;overflow:hidden;"
        }, h(NImage, {
          objectFit: "contain",
          lazy: true,
          "render-toolbar": renderToolbar,
          src: row.Url
        }))
      }
      return [
        h(
            NButton,
            {
              strong: true,
              tertiary: true,
              type: "info",
              size: "small",
              style: {
                margin: "2px"
              },
              onClick: () => {
                if (row.Classify === "audio" || row.Classify === "video" || row.Classify === "m3u8" || row.Classify === "live") {
                  previewRow.value = row
                  showPreviewRow.value = true
                }
              }
            },
            {
              default: () => {
                if (row.Classify === "audio" || row.Classify === "video" || row.Classify === "m3u8" || row.Classify === "live") {
                  return t("index.preview")
                }
                return t("index.preview_tip")
              }
            }
        ),
      ]
    }
  },
  {
    title: computed(() => t("index.status")),
    key: "Status",
    width: 80,
    render: (row: appType.MediaInfo, index: number) => {
      return h(
          NButton,
          {
            tertiary: true,
            type: row.Status === "done" ? "success" : "info",
            size: "small",
            style: {
              margin: "2px"
            },
            onClick: () => {
              if (row.SavePath && row.Status === "done") {
                appApi.openFolder({filePath: row.SavePath})
              } else if (row.Status === "ready") {
                download(row, index)
              }
            }
          },
          {
            default: () => {
              return row.Status === "running" ? row.SavePath : dwStatus.value[row.Status as keyof typeof dwStatus]
            }
          }
      )
    }
  },
  {
    title: () => h('div', {class: 'flex items-center'}, [
      t('index.description'),
      h(NPopover, {
        trigger: 'click',
        placement: 'bottom',
        showArrow: true,
      }, {
        trigger: () => h(NIcon, {
          size: "18",
          class: "ml-1 text-gray-500 cursor-pointer",
          onClick: (e: MouseEvent) => e.stopPropagation()
        }, h(SearchOutline)),
        default: () => h('div', {class: 'p-2 w-64'}, [
          h(NInput, {
            value: descriptionSearchValue.value,
            'onUpdate:value': (val: string) => descriptionSearchValue.value = val,
            placeholder: t('index.search_description'),
            clearable: true
          }, {
            prefix: () => h(NIcon, {component: SearchOutline})
          })
        ])
      })
    ]),
    key: "Description",
    width: 150,
    render: (row: appType.MediaInfo, index: number) => {
      const d = h("div", {class: "ellipsis-2",}, row.Description)
      return h(NTooltip, {trigger: 'hover', placement: 'top'}, {
        trigger: () => d,
        default: () => d
      })
    }
  },
  {
    title: computed(() => t("index.resource_size")),
    key: "Size",
    width: 120,
  },
  {
    title: computed(() => t("index.save_path")),
    key: "SavePath",
    render(row: appType.MediaInfo, index: number) {
      return h("a",
          {
            href: "javascript:;",
            class: "ellipsis-2",
            style: {
              color: "#5a95d0"
            },
            onClick: () => {
              if (row.SavePath && row.Status === "done") {
                appApi.openFolder({filePath: row.SavePath})
              }
            }
          },
          row.Status === "running" ? "" : row.SavePath
      )
    }
  },
  {
    key: "actions",
    width: 130,
    render(row: appType.MediaInfo, index: number) {
      return h(Action, {key: index, row: row, index: index, onAction: dataAction})
    },
    title() {
      return h(ActionDesc)
    }
  }
])

const checkedRowKeysValue = ref<DataTableRowKey[]>([])
const showPreviewRow = ref(false)
const previewRow = ref<appType.MediaInfo>()
const loading = ref(false)
const loadingText = ref("")
const showImport = ref(false)
const showPassword = ref(false)
const downloadQueue = ref<appType.MediaInfo[]>([])
let activeDownloads = 0
let isOpenProxy = false
const processedDownloads = new Set<string>() // 用于跟踪已处理的下载

onMounted(() => {
  try {
    window.addEventListener("resize", () => {
      resetTableHeight()
    })
    loading.value = true
    handleInstall().then((is: boolean) => {
      loading.value = false
    })
  } catch (e) {
    window.$message?.error(JSON.stringify(e), {duration: 5000})
  }

  buildClassify()

  const temp = localStorage.getItem("resources-type")
  if (temp) {
    resourcesType.value = JSON.parse(temp).res
  } else {
    appApi.setType(resourcesType.value)
  }

  const cache = localStorage.getItem("resources-data")
  if (cache) {
    data.value = JSON.parse(cache)
  }
  resetTableHeight()
  
  // 定期检查计数器状态
  setInterval(() => {
    if (activeDownloads < 0) {
      console.log(`[DEBUG] 定期检查：activeDownloads为负数 (${activeDownloads})，重置为0`)
      activeDownloads = 0
    }
  }, 5000) // 每5秒检查一次
  
  eventStore.addHandle({
    type: "newResources",
    event: (res: appType.MediaInfo) => {
      if (store.globalConfig.InsertTail) {
        data.value.push(res)
      } else {
        data.value.unshift(res)
      }
      cacheData()
      
      // 自动下载逻辑
      if (store.globalConfig.AutoDownload && shouldAutoDownload(res)) {
        const index = data.value.findIndex(item => item.Id === res.Id)
        if (index !== -1) {
          console.log(`[DEBUG] 自动下载触发 - ID: ${res.Id}, 当前活跃下载数: ${activeDownloads}`)
          download(res, index)
        }
      }
    }
  })

  eventStore.addHandle({
    type: "downloadProgress",
    event: (res: { Id: string, SavePath: string, Status: string, Message: string }) => {
      switch (res.Status) {
        case "running":
          updateItem(res.Id, item => {
            item.SavePath = res.Message
            item.Status = 'running'
          })
          break
        case "done":
          // 检查是否已经处理过这个下载
          if (processedDownloads.has(res.Id)) {
            console.log(`[DEBUG] 跳过重复的下载完成事件 - ID: ${res.Id}`)
            return
          }
          processedDownloads.add(res.Id)
          
          updateItem(res.Id, item => {
            item.SavePath = res.SavePath
            item.Status = 'done'
          })
          cacheData()
          // 减少活跃下载数并检查队列（只处理一次）
          if (activeDownloads > 0) {
            activeDownloads = Math.max(0, activeDownloads - 1)
            console.log(`[DEBUG] 下载完成事件 - ID: ${res.Id}, 活跃下载数: ${activeDownloads}`)
            checkQueue()
          } else {
            console.log(`[DEBUG] 警告：下载完成事件但activeDownloads已为0 - ID: ${res.Id}`)
            // 强制重置计数器并检查队列
            activeDownloads = 0
            checkQueue()
          }
          break
        case "error":
          // 检查是否已经处理过这个下载
          if (processedDownloads.has(res.Id)) {
            console.log(`[DEBUG] 跳过重复的下载错误事件 - ID: ${res.Id}`)
            return
          }
          processedDownloads.add(res.Id)
          
          updateItem(res.Id, item => {
            item.SavePath = res.Message
            item.Status = 'error'
          })
          cacheData()
          // 减少活跃下载数并检查队列（只处理一次）
          if (activeDownloads > 0) {
            activeDownloads = Math.max(0, activeDownloads - 1)
            console.log(`[DEBUG] 下载错误事件 - ID: ${res.Id}, 活跃下载数: ${activeDownloads}`)
            checkQueue()
          } else {
            console.log(`[DEBUG] 警告：下载错误事件但activeDownloads已为0 - ID: ${res.Id}`)
            // 强制重置计数器并检查队列
            activeDownloads = 0
            checkQueue()
          }
          break
      }
    }
  })
})

watch(() => {
  return store.globalConfig.MimeMap
}, () => {
  buildClassify()
})

watch(resourcesType, (n, o) => {
  localStorage.setItem("resources-type", JSON.stringify({res: resourcesType.value}))
  appApi.setType(resourcesType.value)
})

const updateItem = (id: string, updater: (item: any) => void)=>{
  const item = data.value.find(i => i.Id === id)
  if (item) updater(item)
}

function cacheData() {
  localStorage.setItem("resources-data", JSON.stringify(data.value))
}

const resetTableHeight = () => {
  try {
    const headerHeight = document.getElementById("header")?.offsetHeight || 0
    const bottomHeight = document.getElementById("bottom")?.offsetHeight || 0
    // @ts-ignore
    const theadHeight = document.getElementsByClassName("n-data-table-thead")[0]?.offsetHeight || 0
    const height = document.documentElement.clientHeight || window.innerHeight
    tableHeight.value = height - headerHeight - bottomHeight - theadHeight - 20
  } catch (e) {
    console.log(e)
  }
}

const buildClassify = () => {
  const mimeMap = store.globalConfig.MimeMap ?? {}
  const seen = new Set()
  classify.value = [
    {value: "all", label: computed(() => t("index.all"))},
    ...Object.values(mimeMap)
        .filter(({Type}) => {
          if (seen.has(Type)) return false
          seen.add(Type)
          return true
        })
        .map(({Type}) => ({
          value: Type,
          label: classifyAlias[Type] ?? Type,
        })),
  ]
}

const dataAction = (row: appType.MediaInfo, index: number, type: string) => {
  switch (type) {
    case "down":
      download(row, index)
      break
    case "copy":
      ClipboardSetText(row.Url).then((is: boolean) => {
        if (is) {
          window?.$message?.success(t("common.copy_success"))
        } else {
          window?.$message?.error(t("common.copy_fail"))
        }
      })
      break
    case "json":
      ClipboardSetText(encodeURIComponent(JSON.stringify(row))).then((is: boolean) => {
        if (is) {
          window?.$message?.success(t("common.copy_success"))
        } else {
          window?.$message?.error(t("common.copy_fail"))
        }
      })
      break
    case "open":
      BrowserOpenURL(row.Url)
      break
    case "decode":
      decodeWxFile(row, index)
      break
    case "delete":
      appApi.delete({sign: row.UrlSign}).then(() => {
        data.value.splice(index, 1)
        cacheData()
      })
      break
  }
}

const renderToolbar = ({nodes}: ImageRenderToolbarProps) => {
  return [
    nodes.rotateCounterclockwise,
    nodes.rotateClockwise,
    nodes.resizeToOriginalSize,
    nodes.zoomOut,
    nodes.zoomIn,
    nodes.close
  ]
}

const rowKey = (row: appType.MediaInfo) => {
  return row.Id
}

const handleCheck = (rowKeys: DataTableRowKey[]) => {
  checkedRowKeysValue.value = rowKeys
}

const batchDown = async () => {
  if (checkedRowKeysValue.value.length <= 0) {
    window?.$message?.error(t("index.use_data"))
    return
  }

  if (!store.globalConfig.SaveDirectory) {
    window?.$message?.error(t("index.save_path_empty"))
    return
  }

  // 按列表顺序处理选中的文件
  const selectedItems = data.value
    .filter((item, index) => checkedRowKeysValue.value.includes(item.Id) && item.Classify !== 'live' && item.Classify !== 'm3u8')
    .sort((a, b) => {
      // 按在data中的索引排序，保持列表顺序
      const indexA = data.value.findIndex(item => item.Id === a.Id)
      const indexB = data.value.findIndex(item => item.Id === b.Id)
      return indexA - indexB
    })

  console.log(`[DEBUG] 批量下载 - 选中文件数: ${selectedItems.length}, 当前活跃下载数: ${activeDownloads}`)

  // 逐个下载，让download函数处理队列
  selectedItems.forEach((item, index) => {
    const dataIndex = data.value.findIndex(dataItem => dataItem.Id === item.Id)
    if (dataIndex !== -1) {
      console.log(`[DEBUG] 批量下载第${index + 1}个文件 - ID: ${item.Id}`)
      download(item, dataIndex)
    }
  })

  checkedRowKeysValue.value = []
}

const batchExport = () => {
  if (checkedRowKeysValue.value.length <= 0) {
    window?.$message?.error(t("index.use_data"))
    return
  }

  if (!store.globalConfig.SaveDirectory) {
    window?.$message?.error(t("index.save_path_empty"))
    return
  }

  loadingText.value = t("common.loading")
  loading.value = true

  const jsonData = data.value
      .filter(item => checkedRowKeysValue.value.includes(item.Id))
      .map(item => encodeURIComponent(JSON.stringify(item)))

  appApi.batchExport({content: jsonData.join("\n")}).then((res: appType.Res) => {
    loading.value = false
    if (res.code === 0) {
      window?.$message?.error(res.message)
      return
    }
    window?.$message?.success(t("index.import_success"))
    window?.$message?.info(t("index.save_path") + "：" + res.data?.file_name, {
      duration: 5000
    })
  })
}

const uint8ArrayToBase64 = (bytes: any) => {
  return window.btoa(Array.from(bytes, (byte: any) => String.fromCharCode(byte)).join(''))
}

const download = (row: appType.MediaInfo, index: number) => {
  if (!store.globalConfig.SaveDirectory) {
    window?.$message?.error(t("index.save_path_empty"))
    return
  }

  // 添加关键打印：显示当前下载状态
  console.log(`[DEBUG] 尝试下载 - ID: ${row.Id}, 当前活跃下载数: ${activeDownloads}, 最大并发数: ${maxConcurrentDownloads.value}, 队列长度: ${downloadQueue.value.length}`)

  if (data.value.some(item => item.Id === row.Id && item.Status === "running")) {
    console.log(`[DEBUG] 跳过下载 - ID: ${row.Id}, 原因: 已在运行中`)
    return
  }

  if (downloadQueue.value.some(item => item.Id === row.Id || item.Url === row.Url)) {
    console.log(`[DEBUG] 跳过下载 - ID: ${row.Id}, 原因: 已在队列中`)
    return
  }

  // 检查是否达到并发限制
  if (activeDownloads >= maxConcurrentDownloads.value) {
    console.log(`[DEBUG] 达到并发限制，加入队列 - ID: ${row.Id}, 活跃下载数: ${activeDownloads}, 最大并发数: ${maxConcurrentDownloads.value}`)
    downloadQueue.value.push(row)
    console.log(`[DEBUG] 「${row.Description || '文件'}」已加入下载队列，等待其他下载完成后按顺序下载`)
    return
  }

  console.log(`[DEBUG] 开始下载 - ID: ${row.Id}, 活跃下载数: ${activeDownloads}`)
  startDownload(row, index)
}

const startDownload = (row: appType.MediaInfo, index: number) => {
  activeDownloads++
  console.log(`[DEBUG] 启动下载 - ID: ${row.Id}, 活跃下载数: ${activeDownloads}`)

  const decodeStr = row.DecodeKey
      ? uint8ArrayToBase64(getDecryptionArray(row.DecodeKey))
      : ""

  let wasRejected = false // 标记是否被拒绝

  appApi.download({...row, decodeStr}).then((res: appType.Res) => {
    if (res.code === 0) {
      console.log(`[DEBUG] 下载API返回错误 - ID: ${row.Id}, 错误: ${res.message}`)
      
      // 检查是否是并发限制错误
      if (res.message.includes("并发下载数已达上限") || res.message.includes("下载被拒绝")) {
        console.log(`[DEBUG] 下载被拒绝，加入重试队列 - ID: ${row.Id}`)
        wasRejected = true
        // 将任务重新加入队列，等待其他下载完成后重试
        downloadQueue.value.push(row)
        // 不显示错误信息，静默处理
        console.log(`[DEBUG] 「${row.Description || '文件'}」已加入下载队列，等待其他下载完成后自动重试`)
      } else {
        // 其他错误才显示错误信息
        window?.$message?.error(res.message)
      }
    } else {
      console.log(`[DEBUG] 下载API调用成功 - ID: ${row.Id}`)
    }
  }).catch((error) => {
    console.log(`[DEBUG] 下载API调用异常 - ID: ${row.Id}, 错误: ${error}`)
    window?.$message?.error(`下载失败: ${error}`)
  }).finally(() => {
    // 只有在API调用成功且没有被拒绝时才减少活跃下载数
    // 注意：实际的activeDownloads减少现在在downloadProgress事件中处理
    if (!wasRejected) {
      console.log(`[DEBUG] 下载API调用完成 - ID: ${row.Id}, 等待downloadProgress事件`)
    }
    // 只有在被拒绝时才立即检查队列
    if (wasRejected) {
      checkQueue()
    }
  })
}

const checkQueue = () => {
  console.log(`[DEBUG] 检查队列 - 队列长度: ${downloadQueue.value.length}, 活跃下载数: ${activeDownloads}, 最大并发数: ${maxConcurrentDownloads.value}`)
  
  // 智能重置计数器：如果队列为空且没有活跃下载，但计数器不为0，则重置
  if (downloadQueue.value.length === 0 && activeDownloads < 0) {
    console.log(`[DEBUG] 智能重置：activeDownloads为负数，重置为0`)
    activeDownloads = 0
  }
  
  if (downloadQueue.value.length > 0 && activeDownloads < maxConcurrentDownloads.value) {
    const nextItem = downloadQueue.value.shift()
    if (nextItem) {
      console.log(`[DEBUG] 从队列取出 - ID: ${nextItem.Id}, 队列剩余: ${downloadQueue.value.length}`)
      const index = data.value.findIndex(item => item.Id === nextItem.Id)
      if (index !== -1) {
        console.log(`[DEBUG] 开始处理队列中的文件 - ID: ${nextItem.Id}, 索引: ${index}`)
        startDownload(nextItem, index)
      } else {
        console.log(`[DEBUG] 警告：队列中的文件在data中未找到 - ID: ${nextItem.Id}`)
      }
    }
  } else {
    if (downloadQueue.value.length === 0) {
      console.log(`[DEBUG] 队列为空，无需处理`)
    } else if (activeDownloads >= maxConcurrentDownloads.value) {
      console.log(`[DEBUG] 活跃下载数已达上限，等待下载完成`)
    }
  }
  
  // 定期清理已处理的下载记录（当队列为空且没有活跃下载时）
  if (downloadQueue.value.length === 0 && activeDownloads === 0 && processedDownloads.size > 0) {
    console.log(`[DEBUG] 清理已处理的下载记录，清理前数量: ${processedDownloads.size}`)
    processedDownloads.clear()
  }
}

const open = () => {
  isOpenProxy = true
  store.openProxy().then((res: appType.Res) => {
    if (res.code === 1) {
      return
    }

    if (["darwin", "linux"].includes(store.envInfo.platform)) {
      showPassword.value = true
    } else {
      window.$message?.error(res.message)
    }
  })
}

const close = () => {
  store.unsetProxy()
}

const clear = () => {
  if (checkedRowKeysValue.value.length > 0) {
    let newData = [] as any[]
    data.value.forEach((item, index) => {
      if (checkedRowKeysValue.value.includes(item.Id)) {
        appApi.delete({sign: item.UrlSign})
      } else {
        newData.push(item)
      }
    })
    data.value = newData
    checkedRowKeysValue.value = []
    cacheData()
    return
  }

  data.value = []
  localStorage.setItem("resources-data", "")
  appApi.clear()
}

const decodeWxFile = (row: appType.MediaInfo, index: number) => {
  if (!row.DecodeKey) {
    window?.$message?.error(t("index.video_decode_no"))
    return
  }
  appApi.openFileDialog().then((res: appType.Res) => {
    if (res.code === 0) {
      window?.$message?.error(res.message)
      return
    }
    if (res.data.file) {
      loadingText.value = t("index.video_decode_loading")
      loading.value = true
      appApi.wxFileDecode({
        ...row,
        filename: res.data.file,
        decodeStr: uint8ArrayToBase64(getDecryptionArray(row.DecodeKey))
      }).then((res: appType.Res) => {
        loading.value = false
        if (res.code === 0) {
          window?.$message?.error(res.message)
          return
        }
        data.value[index].SavePath = res.data.save_path
        data.value[index].Status = "done"
        cacheData()
        window?.$message?.success(t("index.video_decode_success"))
      })
    }
  })
}

const handleImport = (content: string) => {
  if (!content) {
    window?.$message?.error(t("view.import_empty"))
    return
  }
  let newItems = [] as any[]
  content.split("\n").forEach((line, index) => {
    try {
      let res = JSON.parse(decodeURIComponent(line))
      if (res && res?.Id) {
        res.Id = res.Id + Math.floor(Math.random() * 100000)
        res.SavePath = ""
        res.Status = "ready"
        newItems.push(res)
      }
    } catch (e) {
      console.log(e)
    }
  })
  if (newItems.length > 0) {
    data.value = [...newItems, ...data.value]
  }
  cacheData()
  showImport.value = false
}

const handlePassword = async (password: string, isCache: boolean) => {
  const res = await appApi.setSystemPassword({password, isCache})
  if (res.code === 0) {
    window.$message?.error(res.message)
    return
  }

  if (isOpenProxy) {
    showPassword.value = false
    store.openProxy()
    return
  }

  handleInstall().then((is: boolean) => {
    if (is) {
      showPassword.value = false
    }
  })
}

const handleInstall = async () => {
  isOpenProxy = false
  const res = await appApi.install()
  if (res.code === 1) {
    store.globalConfig.AutoProxy && store.openProxy()
    return true
  }

  window.$message?.error(res.message, {duration: 5000})

  if (store.envInfo.platform === "windows" && res.message.includes("Access is denied")) {
    window.$message?.error(t("index.win_install_tip"))
  } else if (["darwin", "linux"].includes(store.envInfo.platform)) {
    showPassword.value = true
  }
  return false
}

const toggleAutoDownload = () => {
  store.setConfig({
    AutoDownload: !store.globalConfig.AutoDownload
  })
  window?.$message?.success(
    store.globalConfig.AutoDownload 
      ? t("setting.auto_download") + " " + t("common.enabled")
      : t("setting.auto_download") + " " + t("common.disabled")
  )
}

// 解析视频大小字符串，返回字节数
const parseVideoSize = (sizeStr: string): number => {
  if (!sizeStr) return 0
  
  // 移除所有空格
  sizeStr = sizeStr.replace(/\s/g, '')
  
  // 处理MB
  if (sizeStr.toLowerCase().endsWith('mb')) {
    const size = parseFloat(sizeStr.toLowerCase().replace('mb', ''))
    return size * 1024 * 1024
  }
  
  // 处理KB
  if (sizeStr.toLowerCase().endsWith('kb')) {
    const size = parseFloat(sizeStr.toLowerCase().replace('kb', ''))
    return size * 1024
  }
  
  // 处理B
  if (sizeStr.toLowerCase().endsWith('b')) {
    const size = parseFloat(sizeStr.toLowerCase().replace('b', ''))
    return size
  }
  
  // 如果没有单位，尝试直接解析为字节
  const size = parseFloat(sizeStr)
  return isNaN(size) ? 0 : size
}

// 判断是否应该自动下载
const shouldAutoDownload = (res: appType.MediaInfo): boolean => {
  const rule = store.globalConfig.AutoDownloadRule
  
  // 检查文件类型 - 如果没有选择任何类型，则下载全部类型
  if (rule.EnabledTypes.length > 0 && !rule.EnabledTypes.includes(res.Classify)) {
    return false
  }
  

  
  // 解析文件大小
  const fileSize = parseVideoSize(res.Size)
  if (fileSize === 0) {
    return false // 无法解析大小，不自动下载
  }
  
  // 检查跳过大小限制（0表示不跳过）
  if (rule.SkipSize > 0) {
    const skipSizeBytes = convertSizeToBytes(rule.SkipSize, rule.SizeUnit)
    if (fileSize === skipSizeBytes) {
      return false
    }
  }
  
  // 检查最小大小限制（0表示不限制）
  if (rule.MinSize > 0) {
    const minSizeBytes = convertSizeToBytes(rule.MinSize, rule.SizeUnit)
    if (fileSize < minSizeBytes) {
      return false
    }
  }
  
  // 检查最大大小限制
  const maxSizeBytes = rule.MaxSize > 0 ? convertSizeToBytes(rule.MaxSize, rule.SizeUnit) : Infinity
  if (maxSizeBytes !== Infinity && fileSize > maxSizeBytes) {
    return false
  }
  
  return true
}

// 将指定单位的大小转换为字节
const convertSizeToBytes = (size: number, unit: string): number => {
  switch (unit.toUpperCase()) {
    case 'B':
      return size
    case 'KB':
      return size * 1024
    case 'MB':
      return size * 1024 * 1024
    case 'GB':
      return size * 1024 * 1024 * 1024
    default:
      return size
  }
}
</script>
<style>
.ellipsis-2 {
  display: -webkit-box;
  overflow: hidden;
  text-overflow: ellipsis;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
</style>